/*
 *  
 *  CS_Project
 *
 *  Created by Patrick zulian on 2/22/10.
 *  Copyright 2010 University  of Lugano. All rights reserved.
 *
 */

#ifndef UTILS_UTILS_H
#define UTILS_UTILS_H
#include <iostream>
#include <assert.h>

typedef double scalar;

namespace utils {

	/**
	 *copies an array of type T to dest
	 *@param src
	 *@param dest
	 *@param D size of the arrays
	 */
	
template<typename T, int D>
void copy(T * dest, const T src[]) 
{
	for(int d = 0; d < D; d++) {
		dest[d] = src[d];
	}
}
	
template<typename T, int POWER>
T tpow(const T operand) 
{
	T ret = operand;
	for (int p = 0; p < POWER -1; p++) {
		ret *= operand;
	}
	return ret;
}
	
template<typename T>
T tpow(const T operand, const T power) 
{
	T ret = 1;
	for (int d = 1; d <= power; d++) {
		ret *= operand;
	}
	assert(ret == (int) pow(operand, power));
	return ret;				
}
	
template<typename T>
void shift(T  * arr, const int from, const int to, const int n, const int dir)
{
	assert(from != to && (from + (n*-dir) + dir) >= 0 && ( dir == -1 || dir == 1));
	for (int i = from; from != to; i += dir) {
		for (int j = i; j != from + (n*-dir); j-= dir) {
			arr[j+dir] = arr[j];
		}
	}
}
	
template<typename T, T MULTIPLE>
const T getUpperBound(const T number) {
	assert(MULTIPLE > 1);
	T upperBound = MULTIPLE;
	while (upperBound < number) {
		upperBound *= upperBound;
	}
	return upperBound;
}

	
	/**
	 *@param src the 2D matrix
	 *@param dest the 2D matrix
	 *@param m number of rows
	 *@param n number of columns
	 */
	template<typename T>
	static void
	matrixCopy(T ** src, T ** dest, const int m, const int n) {
		int iter;
		for (iter = 0; iter < m; iter++) {
			copy(src[iter], dest[iter], n);
		}	
	}
	
	/**
	 *@param arr the array that will be initialize to 0
	 *@param size the size of the array
	 */
	template<typename T>
	static void 
	zeros(T * arr, const int size);
	
	
	/**
	 *@param arr the array that will be initialize to 0
	 *@param size the size of the array
	 */
	template <> 
	static void zeros(int *arr, const int size)
	{
		int iter;
		for (iter = 0; iter < size; iter++) {
			arr[iter] = 0;
		}
	}
	
	/**
	 * template specialization for scalars
	 *@param arr the array that will be initialize to 0
	 *@param size the size of the array
	 */
	template <> 
	static void zeros(scalar *arr, const int size)
	{
		int iter;
		for (iter = 0; iter < size; iter++) {
			arr[iter] = 0.0;
		}
	}
	
	/**
	 *@param arr the array that will be initialize to val
	 *@param val the initial value
	 *@param size the extent of the array
	 */
	template<typename T>
	static void initArray(T *arr, const T val, const int size)
	{
		int iter;
		for (iter = 0; iter < size; iter++) {
			arr[iter] = val;
		}
	}
	
	/**
	 *@param as the array that will be printed
	 *@param size the extent of the array
	 */
	template<typename T>
	static void printArray(T * a, const int size) 
	{
		int iter;
		for (iter = 0;  iter < size; iter++) {
			std::cout <<"arr[" << iter <<"] = "<< a[iter] <<std::endl;	
		}
		
	}
	
	/**
	 *@param arr the input array
	 *@param size the extent
	 *@return the sum of all elements of the array
	 */
	template<typename T>
	static T sumArray(T * arr, const int size)
	{
		int iter;
		T sum = arr[0];
		for (iter = 1; iter < size; iter++) {
			sum += arr[iter];
		}
		return sum;
	}
	
	/**
	 *@param src the input array
	 *@param target input and output array
	 *@param size the extent
	 */
	template<typename T>
	static void sumArrays(T * src, T * target, const int size)
	{
		int iter;
		for (iter = 0; iter < size; iter++) {
			target[iter] += src[iter];
		}
		
	}
	
	/**
	 *@param arr the input array
	 *@param size the extent
	 *@return the multiplication of all elements of the array
	 */
	template<typename T>
	static T mulArray(T * arr, const int size)
	{
		int iter;
		T sum = arr[0];
		for (iter = 1; iter < size; iter++) {
			sum *= arr[iter];
		}
		return sum;
	}
	
	
	
	/**
	 *@tparam T is a pointer to some object thus T = *Type
	 *@param left the object that calls compare on the right
	 *@param right the object passed to compare
	 *@return true if left->compare(right) < 0 else false
	 */
	template<typename T >
	struct PComparator {
		bool operator() (const T  &left, const T  &right) const 
		{ 
			const int val = left->compare(right);
			return val < 0; 
		}
	};
	
	
	template<typename C>
	void FreeValues(C &c) 
	{
		typename C::iterator it;
		for ( it = c.begin(); it != c.end(); ++it ) {
			delete *it;
		}
		
	}

}

#endif
